package com.google.checkstyle.test.chapter4formatting.rule4822declaredwhenneeded;

import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;

/** Some javadoc. */
public class InputDeclaredWhenNeeded {

  private static int test1 = 0;

  static {
    int b = 0;
    int d = 0;
    {
      d = ++b;
    }
  }

  static {
    int c = 0;
    int a = 3;
    int b = 2;
    {
      a = a + b;
      c = b;
    }
    {
      c--;
    }
    a = 7;
  }

  static {
    int a = -1;
    int b = 2;
    b++;
    int c = --b;
    a = b; // DECLARATION OF VARIABLE 'a' SHOULD BE HERE (distance = 2)
  }

  /** Some javadoc. */
  public InputDeclaredWhenNeeded(int test1) {
    int temp = -1;
    this.test1 = test1;
    temp = test1; // DECLARATION OF VARIABLE 'temp' SHOULD BE HERE (distance = 2)
  }

  /** Some javadoc. */
  public boolean testMethod() {
    int temp = 7;
    new InputDeclaredWhenNeeded(2);
    String.valueOf(temp); // DECLARATION OF VARIABLE 'temp' SHOULD BE HERE (distance = 2)
    boolean result = false;
    String str = "";
    if (test1 > 1) {
      str = "123";
      result = true;
    }
    return result;
  }

  /** Some javadoc. */
  public void testMethod2() {
    int count;
    int a = 3;
    int b = 2;
    {
      a = a + b - 5 + 2 * a;
      count = b; // DECLARATION OF VARIABLE 'count' SHOULD BE HERE (distance = 2)
    }
  }

  /** Some javadoc. */
  public void testMethod3() {
    int count;
    // violation above 'Distance between variable 'count' .* first usage is 4, but allowed 3.*'
    int a = 3;
    int b = 3;
    a = a + b;
    b = a + a;
    testMethod2();
    count = b; // DECLARATION OF VARIABLE 'count' SHOULD BE HERE (distance = 4)
  }

  /** Some javadoc. */
  public void testMethod4(int arg) {
    int d = 0;
    for (int i = 0; i < 10; i++) {
      d++;
      if (i > 5) {
        d += arg;
      }
    }

    String[] ar = {"1", "2"};
    for (String st : ar) {
      System.identityHashCode(st);
    }
  }

  /** Some javadoc. */
  public void testMethod5() {
    int arg = 7;
    boolean b = true;
    boolean bb = false;
    if (b) {
      if (!bb) {
        b = false;
      }
    }
    testMethod4(arg); // DECLARATION OF VARIABLE 'arg' SHOULD BE HERE (distance = 2)
  }

  /** Some javadoc. */
  public void testMethod6() {
    int blockNumWithSimilarVar = 3;
    int dist = 0;
    int index = 0;
    int block = 0;

    if (blockNumWithSimilarVar <= 1) {
      do {
        dist++;
        if (block > 4) {
          break;
        }
        index++;
        block++;
      } while (index < 7);
    } else {
      while (index < 8) {
        dist += block;
        index++;
        block++;
      }
    }
  }

  /** Some javadoc. */
  public boolean testMethod7(int a) {
    boolean res;
    switch (a) {
      case 1:
        res = true;
        break;
      default:
        res = false;
    }
    return res;
  }

  /** Some javadoc. */
  public void testMethod8() {
    int b = 0;
    int c = 0;
    int m = 0;
    int n = 0;
    {
      c++;
      b++;
    }
    {
      n++; // DECLARATION OF VARIABLE 'n' SHOULD BE HERE (distance = 2)
      m++; // DECLARATION OF VARIABLE 'm' SHOULD BE HERE (distance = 3)
      b++;
    }
  }

  /** Some javadoc. */
  public void testMethod9() {
    boolean result = false;
    boolean b1 = true;
    boolean b2 = false;
    if (b1) {
      if (!b2) {
        result = true;
      }
      result = true;
    }
  }

  /** Some javadoc. */
  public boolean testMethod10() {
    boolean result;
    try {
      result = true;
    } catch (Exception e) {
      result = false;
    } finally {
      result = false;
    }
    return result;
  }

  /** Some javadoc. */
  public void testMethod11() {
    int a = 0;
    int b = 10;
    boolean result;
    try {
      b--;
    } catch (Exception e) {
      b++;
      result = false; // DECLARATION OF VARIABLE 'result' SHOULD BE HERE (distance = 2)
    } finally {
      a++;
    }
  }

  /** Some javadoc. */
  public void testMethod12() {
    boolean result = false;
    boolean b3 = true;
    boolean b1 = true;
    boolean b2 = false;
    if (b1) {
      if (b3) {
        if (!b2) {
          result = true;
        }
        result = true;
      }
    }
  }

  /** Some javadoc. */
  public void testMethod13() {
    int i = 9;
    int j = 6;
    int g = i + 8;
    int k = j + 10;
  }

  /** Some javadoc. */
  public void testMethod14() {
    Session s = openSession();
    Transaction t = s.beginTransaction();
    // violation above 'Distance between variable 't' .* first usage is 5, but allowed 3.'
    A a = new A();
    E d1 = new E();
    C1 c = new C1();
    E d2 = new E();
    a.setForward(d1);
    d1.setReverse(a);
    c.setForward(d2); // DECLARATION OF VARIABLE 'c' SHOULD BE HERE (distance = 3)
    // DECLARATION OF VARIABLE 'd2' SHOULD BE HERE (distance = 3)
    d2.setReverse(c);
    Serializable aid = s.save(a);
    Serializable d2id = s.save(d2);
    t.commit(); // DECLARATION OF VARIABLE 't' SHOULD BE HERE (distance = 5)
    s.close();
  }

  /** Some javadoc. */
  public boolean isCheckBoxEnabled(int path) {
    String model = "";
    if (true) {
      for (int index = 0; index < path; ++index) {
        int nodeIndex = model.codePointAt(path);
        if (model.contains("")) {
          return false;
        }
      }
    } else {
      int nodeIndex = model.codePointAt(path);
      if (model.contains("")) {
        return false;
      }
    }
    return true;
  }

  /** Some javadoc. */
  public Object readObject(String in) throws Exception {
    String startDay = new String("");
    String endDay = new String("");
    return new String(startDay + endDay);
  }

  /** Some javadoc. */
  public int[] getSelectedIndices() {
    int[] sel = new int[5];
    String model = "";
    int a = 0;
    a++;
    for (int index = 0; index < 5; ++index) {
      sel[index] = Integer.parseInt(model.valueOf(a)); // DECLARATION OF VARIABLE 'sel'
      // SHOULD BE HERE (distance = 2)
      // DECLARATION OF VARIABLE 'model'
      // SHOULD BE HERE (distance = 2)
    }
    return sel;
  }

  /** Some javadoc. */
  public void testMethod15() {
    String confDebug = "";
    if (!confDebug.equals("") && !confDebug.equals("null")) {
      LogLog.warn("The \"" + "\" attribute is deprecated.");
      LogLog.warn("Use the \"" + "\" attribute instead.");
      LogLog.setInternalDebugging(confDebug, true);
    }

    int i = 0;
    int k = 7;
    boolean b = false;
    for (; i < k; i++) {
      b = true;
      k++;
    }

    int sw;
    switch (i) {
      case 0:
        k++;
        sw = 0; // DECLARATION OF VARIABLE 'sw' SHOULD BE HERE (distance = 2)
        break;
      case 1:
        b = false;
        break;
      default:
        b = true;
    }

    int wh = 0;
    b = true;
    do {
      k--;
      i++;
    } while (wh > 0); // DECLARATION OF VARIABLE 'wh' SHOULD BE HERE (distance = 2)

    if (wh > 0) {
      k++;
    } else if (!b) {
      i++;
    } else {
      i--;
    }
  }

  /** Some javadoc. */
  public void testMethod16() {
    int wh = 1;
    int i = 0;
    int k = 7;
    if (i > 0) {
      k++;
    } else if (wh > 0) {
      i++;
    } else {
      i--;
    }
  }

  /** Some javadoc. */
  protected JmenuItem createSubMenuItem(LogLevel level) {
    final JmenuItem result = new JmenuItem(level.toString());
    final LogLevel logLevel = level;
    result.setMnemonic(level.toString().charAt(0));
    result.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            showLogLevelColorChangeDialog(result, logLevel);
            // DECLARATION OF VARIABLE 'logLevel', SHOULD BE HERE (distance = 2)
          }
        });

    return result;
  }

  /** Some javadoc. */
  public static Color darker(Color color, double fraction) {
    int red = (int) Math.round(color.getRed() * (1.0 - fraction));
    int green = (int) Math.round(color.getGreen() * (1.0 - fraction));
    int blue = (int) Math.round(color.getBlue() * (1.0 - fraction));

    if (red < 0) {
      red = 0;
    } else if (red > 255) {
      red = 255;
    }
    if (green < 0) { // DECLARATION OF VARIABLE 'green' SHOULD BE HERE (distance = 2)
      green = 0;
    } else if (green > 255) {
      green = 255;
    }
    if (blue < 0) { // DECLARATION OF VARIABLE 'blue' SHOULD BE HERE (distance = 3)
      // blue = 0;
    }

    int alpha = color.getAlpha();

    return new Color(red, green, blue, alpha);
  }

  /** Some javadoc. */
  public void testFinal() {
    AuthUpdateTask task = null;
    final long intervalMs = 30 * 60000L;
    Object authCheckUrl = null;
    Object authInfo = null;
    task =
        new AuthUpdateTask(
            authCheckUrl,
            authInfo,
            new IauthListener() {
              @Override
              public void authTokenChanged(String cookie, String token) {
                fireAuthTokenChanged(cookie, token);
              }
            });

    Timer timer = new Timer("Auth Guard", true);
    timer.schedule(task, intervalMs / 2, intervalMs); // DECLARATION OF VARIABLE 'intervalMs'
    // SHOULD BE HERE (distance = 2)
  }

  /** Some javadoc. */
  public void testForCycle() {
    int filterCount = 0;
    for (int i = 0; i < 10; i++, filterCount++) {
      int abc = 0;
      System.identityHashCode(abc);

      for (int j = 0; j < 10; j++) {
        abc = filterCount;
        System.identityHashCode(abc);
      }
    }
  }

  /** Some javadoc. */
  public void testIssue321() {
    Option srcDdlFile = OptionBuilder.create("f");
    Option logDdlFile = OptionBuilder.create("o");
    Option help = OptionBuilder.create("h");

    Options options = new Options();
    options.something();
    options.something();
    options.something();
    options.something();
    options.addOption(srcDdlFile, logDdlFile, help); // distance=1
  }

  /** Some javadoc. */
  public void testIssue322() {
    int mm = Integer.parseInt("2");
    long timeNow = 0;
    Calendar cal = Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault());
    cal.setTimeInMillis(timeNow);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    cal.set(Calendar.HOUR_OF_DAY, mm);
    cal.set(Calendar.MINUTE, mm); // distance=1
  }

  /** Some javadoc. */
  public void testIssue323(MyObject[] objects) {
    Calendar cal = Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault());
    for (int i = 0; i < objects.length; i++) {
      objects[i].setEnabled(true);
      objects[i].setColor(0x121212);
      objects[i].setUrl("http://google.com");
      objects[i].setSize(789);
      objects[i].setCalendar(cal); // distance=1
    }
  }

  /** Some javadoc. */
  public String testIssue324(boolean flag) {
    StringBuilder builder = new StringBuilder();
    builder.append("flag is ");
    builder.append(flag);
    final String line = "";
    if (flag) {
      builder.append("line of AST is:");
      builder.append("\n");
      builder.append(String.valueOf(line)); // distance=1
      builder.append("\n");
    }
    return builder.toString();
  }

  /** Some javadoc. */
  public void testIssue325() {
    Option a = null;
    Option b = null;
    Option c = null;
    boolean isCnull = isNull(c); // distance=1
    boolean isBnull = isNull(b); // distance=1
    boolean isAnull = isNull(a); // distance=1
  }

  /** Some javadoc. */
  public void testIssue326() {
    Option aopt = null;
    Option bopt = null;
    Option copt = null;
    isNull(copt); // distance = 1
    isNull(bopt); // distance = 2
    isNull(aopt); // distance = 3
  }

  /** Some javadoc. */
  public void testIssue327() {
    String line = "abc";
    OtherWriter.write(line);
    line.charAt(1);
    Builder.append(line);
    test(line, line, line);
  }

  /** Some javadoc. */
  public void testIssue328(Writer w1, Writer w2, Writer w3) {
    String l1 = "1";

    w3.write(l1); // distance=3
  }

  /** Some javadoc. */
  public void testIssue329() {
    Options options = new Options();
    Option myOption = null;
    // violation above 'Distance between variable 'myOption' .* usage is 7, but allowed 3.'
    options.addBindFile(null);
    options.addBindFile(null);
    options.addBindFile(null);
    options.addBindFile(null);
    options.addBindFile(null);
    System.identityHashCode("message");
    myOption.setArgName("abc"); // distance=7
  }

  /** Some javadoc. */
  public void testIssue3210() {
    Options options = new Options();
    Option myOption = null;
    // violation above 'Distance between variable 'myOption' .* usage is 6, but allowed 3.'
    options.addBindFile(null);
    options.addBindFile(null);
    options.addBindFile(null);
    options.addBindFile(null);
    options.addBindFile(null);
    myOption.setArgName("q"); // distance=6
  }

  /** Some javadoc. */
  public int testIssue3211(String toDir) throws Exception {
    int count = 0;
    // violation above 'Distance between variable 'count' .* first usage is 4, but allowed 3.'
    String[] files = {};

    System.identityHashCode("Data archival started");
    files.notify();
    System.identityHashCode("sss");

    if (files == null || files.length == 0) {
      System.identityHashCode("No files on a remote site");
    } else {
      System.identityHashCode("Files on remote site: " + files.length);

      for (String ftpFile : files) {
        if (files.length == 0) {
          "".concat("");
          ftpFile.concat(files[2]);
          count++;
        }
      }
    }

    System.lineSeparator();

    return count;
  }

  private Session openSession() {
    return null;
  }

  class Session {

    public Transaction beginTransaction() {
      return null;
    }

    public void close() {}

    public Serializable save(E d2) {
      return null;
    }

    public Serializable save(A a) {
      return null;
    }
  }

  class Transaction {

    public void commit() {}
  }

  class A {

    public void setForward(E d1) {}
  }

  class E {

    public void setReverse(C1 c) {}

    public void setReverse(A a) {}
  }

  class C1 {

    public void setForward(E d2) {}
  }

  class Serializable {}

  class JmenuItem {

    public JmenuItem(String string) {}

    public void addActionListener(ActionListener actionListener) {}

    public void setMnemonic(char charAt) {}
  }

  class LogLevel {}

  class ActionListener {}

  class ActionEvent {}

  private void showLogLevelColorChangeDialog(JmenuItem j, LogLevel l) {}

  static class Color {

    public Color(int red, int green, int blue, int alpha) {}

    public double getRed() {
      return 0;
    }

    public int getAlpha() {
      return 0;
    }

    public double getBlue() {
      return 0;
    }

    public double getGreen() {
      return 0;
    }
  }

  class AuthUpdateTask {

    public AuthUpdateTask(Object authCheckUrl, Object authInfo, IauthListener authListener) {}
  }

  interface IauthListener {

    void authTokenChanged(String cookie, String token);
  }

  void fireAuthTokenChanged(String s, String s1) {}

  class Timer {

    public Timer(String string, boolean b) {}

    public void schedule(AuthUpdateTask authUpdateTask, long l, long intervalMs) {}
  }

  class Option {

    public void setArgName(String string) {}
  }

  boolean isNull(Option o) {
    return false;
  }

  class Writer {

    public void write(String l3) {}
  }

  class Options {

    public void addBindFile(Object object) {}

    public void addOption(Option srcDdlFile, Option logDdlFile, Option help) {}

    public void something() {}
  }

  class TreeMapNode {

    public TreeMapNode(String label, double d, DefaultValue defaultValue) {}

    public TreeMapNode(String label) {}
  }

  class DefaultValue {

    public DefaultValue(double d) {}
  }

  static class LogLog {

    public static void warn(String string) {}

    public static void setInternalDebugging(String confDebug, boolean b) {}
  }

  static class OptionBuilder {

    public static Option create(String string) {
      return null;
    }
  }

  class MyObject {

    public void setEnabled(boolean b) {}

    public void setCalendar(Calendar cal) {}

    public void setSize(int i) {}

    public void setUrl(String string) {}

    public void setColor(int i) {}
  }

  static class OtherWriter {

    public static void write(String line) {}
  }

  void test(String s, String s1, String s2) {}

  static class Builder {

    public static void append(String line) {}
  }
}
